﻿using System;
using System.Collections;
using System.Web.UI;
using BaseClasses;
using BaseClasses.Data;
using BaseClasses.Utils;
using EnGasAdoAPP.Data;

namespace EnGasAdoAPP.UI
// Typical customizations that may be done in this class include
// - adding custom event handlers
//  - overriding base class methods

/// <summary>
/// The superclass (i.e. base class) for all Designer-generated pages in this application.
/// </summary>
/// <remarks>
/// <para>
/// </para>
/// </remarks>
{
    public class BaseApplicationTableControl : System.Web.UI.Control
    {
        public BaseApplicationTableControl()
        {
            this.PreRender += new EventHandler(Control_ClearControls_PreRender);
            this.Unload += new EventHandler(Control_SaveControls_Unload);
        }

        /// <summary>
        /// The name of the row controls. By convention, "Row" is appended to the
        /// end of the name of the table control. So OrdersTableControl will have
        /// OrdersTableControlRow controls.
        /// </summary>
        public virtual string RowName
        {
            get { return this.ID + "Row"; }
        }

        /// <summary>
        /// The name of the repeater controls. By convention, "Repeater" is appended to the
        /// end of the name of the table control. So OrdersTableControl will have
        /// OrdersTableControlRepeater controls. The Row controls defined above are
        /// within the Repeater control.
        /// </summary>
        public virtual string RepeaterName
        {
            get { return this.ID + "Repeater"; }
        }

        // Allow for migration from earlier versions which did not have url encryption.
        public virtual string ModifyRedirectUrl(string redirectUrl, string redirectArgument)
        {
            throw new Exception("This function should be implemented by inherited table control class.");
        }

        public virtual string ModifyRedirectUrl(string redirectUrl, string redirectArgument, bool bEncrypt)
        {
            throw new Exception("This function should be implemented by inherited table control class.");
        }

        public virtual string EvaluateExpressions(string redirectUrl, string redirectArgument, bool bEncrypt)
        {
            throw new Exception("This function should be implemented by inherited table control class.");
        }

        // Allow for migration from earlier versions which did not have url encryption.
        public virtual string ModifyRedirectUrl(string redirectUrl, string redirectArgument, Object rec)
        {
            return EvaluateExpressions(redirectUrl, redirectArgument, rec, false);
        }

        public virtual string ModifyRedirectUrl(string redirectUrl, string redirectArgument, Object rec, bool bEncrypt)
        {
            return EvaluateExpressions(redirectUrl, redirectArgument, rec, bEncrypt);
        }


        public virtual string EvaluateExpressions(string redirectUrl, string redirectArgument, Object rec, bool bEncrypt)
        {
            const string PREFIX_NO_ENCODE = "NoUrlEncode:";

            string finalRedirectUrl = redirectUrl;
            string finalRedirectArgument = redirectArgument;

            if ((finalRedirectUrl == null || finalRedirectUrl.Length == 0))
            {
                return finalRedirectUrl;
            }
            else if (finalRedirectUrl.IndexOf('{') < 0)
            {
                return finalRedirectUrl;
            }
            else
            {
                //The old way was to pass separate URL and arguments and use String.Format to
                //do the replacement. Example:
                // URL: EditProductsRecord?Products={0}
                // Argument: PK
                //The new way to is pass the arguments directly in the URL. Example:
                // URL: EditProductsRecord?Products={PK}
                //If the old way is passsed, convert it to the new way.
                if (finalRedirectArgument != null && finalRedirectArgument.Length > 0)
                {
                    string[] arguments = finalRedirectArgument.Split(',');
                    for (int i = 0; i <= (arguments.Length - 1); i++)
                    {
                        finalRedirectUrl = finalRedirectUrl.Replace("{" + i.ToString() + "}", "{" + arguments[i] + "}");
                    }
                    finalRedirectArgument = "";
                }

                //Evaluate all of the expressions in the RedirectURL
                //Expressions can be of the form [ControlName:][NoUrlEncode:]Key[:Value]
                string remainingUrl = finalRedirectUrl;

                while ((remainingUrl.IndexOf('{') >= 0) & (remainingUrl.IndexOf('}') > 0) & (remainingUrl.IndexOf('{') < remainingUrl.IndexOf('}')))
                {

                    int leftIndex = remainingUrl.IndexOf('{');
                    int rightIndex = remainingUrl.IndexOf('}');
                    string expression = remainingUrl.Substring(leftIndex + 1, rightIndex - leftIndex - 1);
                    string origExpression = expression;
                    remainingUrl = remainingUrl.Substring(rightIndex + 1);

                    bool skip = false;
                    bool returnEmptyStringOnFail = false;
                    string prefix = null;

                    //Check to see if this control must evaluate the expression
                    if ((expression.IndexOf(":") > 0))
                    {
                        prefix = expression.Substring(0, expression.IndexOf(":"));
                    }
                    if ((prefix != null) && (prefix.Length > 0) && (!(StringUtils.InvariantLCase(prefix) == StringUtils.InvariantLCase(PREFIX_NO_ENCODE))) && (!BaseRecord.IsKnownExpressionPrefix(prefix)))
                    {

                        //Remove the ASCX Prefix
                        string IdString = this.ID;
                        if (IdString.StartsWith("_"))
                        {
                            IdString = IdString.Remove(0, 1);
                        }
                        //The prefix is a control name.
                        if (prefix == IdString)
                        {
                            //This control is responsible for evaluating the expression,
                            //so if it can't be evaluated then return an empty string.
                            returnEmptyStringOnFail = true;
                            expression = expression.Substring(expression.IndexOf(":") + 1);
                        }
                        else
                        {
                            //It's not for this control to evaluate so skip.
                            skip = true;
                        }
                    }

                    if (!skip)
                    {
                        bool bUrlEncode = true;
                        if (StringUtils.InvariantLCase(expression).StartsWith(StringUtils.InvariantLCase(PREFIX_NO_ENCODE)))
                        {
                            bUrlEncode = false;
                            expression = expression.Substring(PREFIX_NO_ENCODE.Length);
                        }
                        object result = null;
                        try
                        {
                            if (rec != null)
                            {
                                result = ((IRecord)rec).EvaluateExpression(expression);
                            }
                        }
                        catch (Exception)
                        {
                            //Fall through
                        }

                        if (result != null)
                        {
                            result = result.ToString();
                        }
                        if (result == null)
                        {
                            if (!returnEmptyStringOnFail)
                            {
                                return finalRedirectUrl;
                            }
                            else
                            {
                                result = string.Empty;
                            }
                        }
                        
                        if (bUrlEncode)
                        {
                            result = System.Web.HttpUtility.UrlEncode((string)result);
                            if (result == null)
                            {
                                result = string.Empty;
                            }
                        }
                        if (bEncrypt)
                        {
                            if (result != null)
                            {
                                result = ((BaseApplicationPage)this.Page).Encrypt((string)result);
                            }
                        }
                        finalRedirectUrl = finalRedirectUrl.Replace("{" + origExpression + "}", (string)result);
                    }
                }
            }

            //If there are still expressions to evaluate. Forward to the page for further processing.
            return finalRedirectUrl;
        }
        public bool AreAnyUrlParametersForMe(string url, string arg)
        {
            const string PREFIX_NO_ENCODE = "NoUrlEncode:";
            string finalRedirectUrl = url;
            string finalRedirectArgument = url;
            bool skip = false;
            if (finalRedirectArgument != null && finalRedirectArgument.Length > 0)
            {
                string[] arguments = finalRedirectArgument.Split(',');
                for (int i = 0; i <= (arguments.Length - 1); i++)
                {
                    finalRedirectUrl = finalRedirectUrl.Replace("{" + i.ToString() + "}", "{" + arguments[i] + "}");
                }
                finalRedirectArgument = "";
            }
            // Evaluate all of the expressions in the RedirectURL
            // Expressions can be of the form [ControlName:][NoUrlEncode:]Key[:Value]
            string remainingUrl = finalRedirectUrl;
            while ((remainingUrl.IndexOf('{') > 0) & (remainingUrl.IndexOf('}') > 0) & (remainingUrl.IndexOf('{') < remainingUrl.IndexOf('}')))
            {
                int leftIndex = remainingUrl.IndexOf('{');
                int rightIndex = remainingUrl.IndexOf('}');
                string expression = remainingUrl.Substring(leftIndex + 1, rightIndex - leftIndex - 1);
                string origExpression = expression;
                remainingUrl = remainingUrl.Substring(rightIndex + 1);
                string prefix = null;
                if (expression.IndexOf(":") > 0)
                {
                    prefix = expression.Substring(0, expression.IndexOf(":"));
                }
                if ((prefix != null) && (prefix.Length > 0) && (!((StringUtils.InvariantLCase(prefix) == StringUtils.InvariantLCase(PREFIX_NO_ENCODE)))) && (!(BaseRecord.IsKnownExpressionPrefix(prefix))))
                {
                    if (prefix == this.ID)
                    {
                        skip = false;
                        break;
                    }
                    else
                    {
                        skip = true;
                    }
                }
            }

            if (skip)
            {
                return false;
            }

            return true;

        }

        #region " Methods to manage saving and retrieving control values to session. "

        protected void Control_SaveControls_Unload(object sender, EventArgs e)
        {
            if (((BaseApplicationPage)(this.Page)).ShouldSaveControlsToSession)
            {
                this.SaveControlsToSession();
            }
        }

        protected virtual void SaveControlsToSession()
        {
        }

        protected void Control_ClearControls_PreRender(object sender, EventArgs e)
        {
            this.ClearControlsFromSession();
        }

        protected virtual void ClearControlsFromSession()
        {
        }

        public void SaveToSession(Control control, string value)
        {
            SaveToSession(control.UniqueID, value);
        }

        public string GetFromSession(Control control, string defaultValue)
        {
            return GetFromSession(control.UniqueID, defaultValue);
        }

        public string GetFromSession(Control control)
        {
            return GetFromSession(control.UniqueID, null);
        }

        public void RemoveFromSession(Control control)
        {
            RemoveFromSession(control.UniqueID);
        }

        public bool InSession(Control control)
        {
            return InSession(control.UniqueID);
        }

        public void SaveToSession(Control control, string variable, string value)
        {
            SaveToSession(control.UniqueID + variable, value);
        }

        public string GetFromSession(Control control, string variable, string defaultValue)
        {
            return GetFromSession(control.UniqueID + variable, defaultValue);
        }

        public void RemoveFromSession(Control control, string variable)
        {
            RemoveFromSession(control.UniqueID + variable);
        }

        public bool InSession(Control control, string variable)
        {
            return InSession(control.UniqueID + variable);
        }

        public void SaveToSession(string name, string value)
        {
            this.Page.Session[GetValueKey(name)] = value;
        }

        public string GetFromSession(string name, string defaultValue)
        {
            string value = ((string)(this.Page.Session[GetValueKey(name)]));
            if (value == null || value.Length == 0)
            {
                value = defaultValue;
            }
            return value;
        }

        public string GetFromSession(string name)
        {
            return GetFromSession(name, null);
        }

        public void RemoveFromSession(string name)
        {
            this.Page.Session.Remove(GetValueKey(name));
        }

        public bool InSession(string name)
        {
            return (!(this.Page.Session[GetValueKey(name)] == null));
        }

        public string GetValueKey(string name)
        {
            return this.Page.Session.SessionID + this.Page.AppRelativeVirtualPath + name;
        }
        /// <summary>
        /// This function returns the list of record controls within the table control.
        /// There is a more specific GetRecordControls function generated in the 
        /// derived classes, but in some cases, we do not know the specific type of
        /// the table control, so we need to call this method. This is also used by the
        /// Formula evaluator to perform Sum, Count and CountA functions.
        /// </summary>
        public BaseApplicationRecordControl[] GetBaseRecordControls()
        {
            ArrayList recList = new ArrayList();

            // First get the repeater inside the Table Control.
            System.Web.UI.WebControls.Repeater rep = (System.Web.UI.WebControls.Repeater)this.FindControl(this.RepeaterName);
            if ((rep == null) || (rep.Items == null)) return null;

            // We now go inside the repeater to find all the record controls. 
            // Note that we only find the first level record controls. We do not
            // descend down and find other record controls belonging to tables-inside-table.

            foreach (System.Web.UI.WebControls.RepeaterItem repItem in rep.Items)
            {
                BaseApplicationRecordControl recControl = (BaseApplicationRecordControl)repItem.FindControl(this.RowName);
                if (!((recControl == null))) recList.Add(recControl);
            }

            return (BaseApplicationRecordControl[])recList.ToArray(typeof(BaseApplicationRecordControl));
        }

        /// <summary>
        /// Sum the values of the displayed controls. The controlName must be
        /// a textbox, label or literal.
        /// This function is called as [Products]TableControl.SUM("UnitPrice").
        /// To make sure all the formula functions are in the same location, we call
        /// the SUM function in the FormulaUtils class, which actually does the work
        /// and return the value. The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total of adding the value contained in each of the fields.</returns>
        public decimal Sum(string controlName)
        {
            return FormulaUtils.Sum(this, controlName);
        }

        /// <summary>
        /// Sum the values of the displayed controls.  The controlName must be
        /// a textbox, label or literal.
        /// This function is called as [Products]TableControl.TOTAL("UnitPrice").
        /// To make sure all the formula functions are in the same location, we call
        /// the TOTAL function in the FormulaUtils class, which actually does the work
        /// and return the value.  The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total of adding the value contained in each of the fields.</returns>
        public decimal Total(string controlName)
        {
            return FormulaUtils.Total(this, controlName);
        }

        /// <summary>
        /// Finds the maximum among the values of the displayed controls.  The ctlName must be
        /// a textbox, label or literal.
        /// This function should be called as [Products]TableControl.Max("UnitPrice"), not
        /// as shown here. The MAX function in the BaseApplicationTableControl will call this
        /// function to actually perform the work - so that we can keep all of the formula
        /// functions together in one place.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The maximum among the values contained in each of the fields.</returns>
        public decimal Max(string controlName)
        {
            return FormulaUtils.Max(this, controlName);
        }        

        /// <summary>
        /// Finds the minimum among the values of the displayed controls.  The ctlName must be
        /// a textbox, label or literal.
        /// This function should be called as [Products]TableControl.Min("UnitPrice"), not
        /// as shown here. The MIN function in the BaseApplicationTableControl will call this
        /// function to actually perform the work - so that we can keep all of the formula
        /// functions together in one place.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The minimum among the values contained in each of the fields.</returns>
        public decimal Min(string controlName)
        {
            return FormulaUtils.Min(this, controlName);
        }        

        /// <summary>
        /// Count the number of rows in the table control. 
        /// This function is called as [Products]TableControl.COUNT().
        /// To make sure all the formula functions are in the same location, we call
        /// the COUNT function in the FormulaUtils class, which actually does the work
        /// and return the value. The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total number of rows in the table control.</returns>
        public decimal Count(string controlName)
        {
            return FormulaUtils.Count(this, controlName);
        }

        /// <summary>
        /// Count the number of rows in the table control that are non-blank.
        /// This function is called as [Products]TableControl.COUNTA().
        /// To make sure all the formula functions are in the same location, we call
        /// the COUNTA function in the FormulaUtils class, which actually does the work
        /// and return the value. The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total number of rows in the table control.</returns>
        public decimal CountA(string controlName)
        {
            return FormulaUtils.CountA(this, controlName);
        }

        /// <summary>
        /// Mean of the rows in the table control.
        /// This function is called as [Product]TableControl.COUNTA().
        /// To make sure all the formula functions are in the same location, we call
        /// the MEAN function in the FormulaUtils class, which actually does the work
        /// and return the value. The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total number of rows in the table control.</returns>
        public decimal Mean(string controlName)
        {
            return FormulaUtils.Mean(this, controlName);
        }

        /// <summary>
        /// Average of the rows in the table control.
        /// This function is called as [Product]TableControl.COUNTA().
        /// To make sure all the formula functions are in the same location, we call
        /// the AVERAGE function in the FormulaUtils class, which actually does the work
        /// and return the value. The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total number of rows in the table control.</returns>
        public decimal Average(string controlName)
        {
            return FormulaUtils.Average(this, controlName);
        }

        /// <summary>
        /// Mode of the rows in the table control.
        /// This function is called as [Product]TableControl.COUNTA().
        /// To make sure all the formula functions are in the same location, we call
        /// the MODE function in the FormulaUtils class, which actually does the work
        /// and return the value. The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total number of rows in the table control.</returns>
        public decimal Mode(string controlName)
        {
            return FormulaUtils.Mode(this, controlName);
        }

        /// <summary>
        /// Median of the rows in the table control.
        /// This function is called as [Product]TableControl.COUNTA().
        /// To make sure all the formula functions are in the same location, we call
        /// the MEDIAN function in the FormulaUtils class, which actually does the work
        /// and return the value. The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total number of rows in the table control.</returns>
        public decimal Median(string controlName)
        {
            return FormulaUtils.Median(this, controlName);
        }

        /// <summary>
        /// Range of the rows in the table control.
        /// This function is called as [Product]TableControl.COUNTA().
        /// To make sure all the formula functions are in the same location, we call
        /// the RANGE function in the FormulaUtils class, which actually does the work
        /// and return the value. The function in FormulaUtils will need to know the
        /// TableControl, so it is passed as the first instance.
        /// </summary>
        /// <param name="controlName">The string name of the UI control (e.g., "UnitPrice") </param>
        /// <returns>The total number of rows in the table control.</returns>
        public decimal Range(string controlName)
        {
            return FormulaUtils.Range(this, controlName);
        }
        #endregion
    }
}